#include <nlohmann/json.hpp>
#include <fstream>

namespace nlohmann
{
    template<>
    struct adl_serializer< hy::RobotWorkFlowTask>
    {
        static void to_json(json& j, const hy::RobotWorkFlowTask& v)
        {
            //std::string t;
            //switch (v.Type)
            //{
            //case ROBOT_WORKFLOW_RUNTIME_POSE:
            //    t = "RuntimePose";
            //    break;
            //case ROBOT_WORKFLOW_IO_TASK:
            //    t = "IOTask";
            //    break;
            //default:
            //    t = "PresetPose";
            //    break;
            //}
            j = json{ {"Type", v.Type}, {"Name", v.Name}, {"Size", v.Size} };
        }

        static void from_json(const json& j, RobotWorkFlowTask& v)
        {
            //std::string t;
            //j.at("Type").get_to(t);
            //if (t == "RuntimePose")
            //    v.Type = ROBOT_WORKFLOW_RUNTIME_POSE;
            //else if (t == "IOTask")
            //    v.Type = ROBOT_WORKFLOW_IO_TASK;
            //else
            //    v.Type = ROBOT_WORKFLOW_PRESET_POSE;
            j.at("Type").get_to(v.Type);
            j.at("Name").get_to(v.Name);
            j.at("Size").get_to(v.Size);
        }
    };

    template<>
    struct adl_serializer< hy::HYRobotIOTask>
    {
        static void to_json(json& j, const hy::HYRobotIOTask& v)
        {
            //std::string a;
            //switch (v.Action)
            //{
            //case ROBOT_IO_ACTION_SET:
            //    a = "Set";
            //    break;
            //case ROBOT_IO_ACTION_WAIT_MS:
            //    a = "Wait";
            //    break;
            //default:
            //    a = "Get";
            //    break;
            //}
            //std::string t;
            //switch (v.Type)
            //{
            //case ROBOT_IO_TYPE_AI:
            //    t = "AI";
            //    break;
            //case ROBOT_IO_TYPE_AO:
            //    t = "AO";
            //    break;
            //case ROBOT_IO_TYPE_DI:
            //    t = "DI";
            //    break;
            //case ROBOT_IO_TYPE_DO:
            //    t = "DO";
            //    break;
            //default:
            //    t = "VAL";
            //    break;
            //}
            j = json{ {"Action", v.Action}, {"Type", v.Type}, {"Name", v.Name}, {"Value", v.Value} };
        }

        static void from_json(const json& j, HYRobotIOTask& v)
        {
            //std::string a;
            //j.at("Action").get_to(a);
            //if (a == "SetIO")
            //    v.Action = ROBOT_IO_ACTION_SET;
            //else if (a == "WaitMS")
            //    v.Action = ROBOT_IO_ACTION_WAIT_MS;
            //else
            //    v.Action = ROBOT_IO_ACTION_GET;
            j.at("Action").get_to(v.Action);
            //std::string t;
            //j.at("Type").get_to(t);
            //if (t == "AI")
            //    v.Type = ROBOT_IO_TYPE_AI;
            //else if (t == "AO")
            //    v.Type = ROBOT_IO_TYPE_AO;
            //else if (t == "DI")
            //    v.Type = ROBOT_IO_TYPE_DI;
            //else if (t == "DO")
            //    v.Type = ROBOT_IO_TYPE_DO;
            //else
            //    v.Type = ROBOT_IO_TYPE_VAL;
            j.at("Type").get_to(v.Type);
            j.at("Name").get_to(v.Name);
            j.at("Value").get_to(v.Value);
        }
    };

    template<>
    struct adl_serializer< hy::RobotPose>
    {
        static void to_json(json& j, const hy::RobotPose& v)
        {
            //std::string t;
            //if (v.Type == ROBOT_POSE_CARTESIAN)
            //    t = "Cartesian";
            //else
            //    t = "Joint";
            j = json{ {"Type", v.Type}, {"Value", v.Value} };
        }

        static void from_json(const json& j, RobotPose& v)
        {
            //std::string t;
            //j.at("Type").get_to(t);
            //if (t == "Joint")
            //    v.Type = ROBOT_POSE_JOINT;
            //else
            //    v.Type = ROBOT_POSE_CARTESIAN;
            j.at("Type").get_to(v.Type);
            j.at("Value").get_to(v.Value);
        }
    };
}

size_t RobotWorkFlow::runtimePoseCount()
{
    size_t count = 0;
    for (const RobotWorkFlowTask& task : WorkFlow)
    {
        if (task.Type == ROBOT_WORKFLOW_RUNTIME_POSE)
            count += task.Size;
    }
    return count;
}

int RobotWorkFlow::save(const std::string& file) const
{
    try
    {
        nlohmann::json json = { {"WorkFlow", WorkFlow}, {"IOTask", IOTask}, {"PresetPose", PresetPose}, {"RandomRadius", RandomRadius} };
        std::ofstream(file) << json.dump(4);
        return HY_SUCESS;
    }
    catch (const std::exception& ex)
    {
        HY_LOG_E("save workflow file {} catch exception: {}", file, ex.what());
        return HY_FAIL_EXCEPTION;
    }
}

int RobotWorkFlow::load(const std::string& file)
{
    try
    {
        nlohmann::json json;
        std::ifstream(file) >> json;
        json.at("WorkFlow").get_to(WorkFlow);
        json.at("IOTask").get_to(IOTask);
        json.at("PresetPose").get_to(PresetPose);
        json.at("RandomRadius").get_to(RandomRadius);

        return HY_SUCESS;
    }
    catch (const std::exception& ex)
    {
        HY_LOG_E("load workflow file {} catch exception: {}", file, ex.what());
        return HY_FAIL_EXCEPTION;
    }
}
